/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#ifndef __MODEL__
#define __MODEL__

#include "modelgen.h"
#include "spritegn.h"

/*

d*_t structures are on-disk representations
m*_t structures are in-memory

*/

// entity effects

#define	EF_BRIGHTFIELD			1
#define	EF_MUZZLEFLASH 			2
#define	EF_BRIGHTLIGHT 			4
#define	EF_DIMLIGHT 			8
#define EF_BLUE					64
#define EF_RED					128
#define	EF_GREEN				32
#define EF_FULLDYNAMIC			16


/*
==============================================================================

BRUSH MODELS

==============================================================================
*/


//
// in memory representation
//
typedef struct
{
    vec3_t		position;
} mvertex_t;


//PENTA: "modern" vertices
//WARNING: if you change the size of this also change VERTEXSIZE
typedef struct
{
    vec3_t		position;
    float		texture[2];
    float		lightmap[2];
} mmvertex_t;


#define	SIDE_FRONT	0
#define	SIDE_BACK	1
#define	SIDE_ON		2


// plane_t structure
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct mplane_s
{
    vec3_t	normal;
    float	dist;
    byte	type;			// for texture axis selection and fast side tests
    byte	signbits;		// signx + signy<<1 + signz<<1
    byte	pad[2];
} mplane_t;

typedef struct texture_s
{
    char		        name[16];
    unsigned	        width, height;
    int			        gl_texturenum;
    int			        gl_lumatexturenum;
    struct msurface_s	*texturechain;	        // for gl_texsort drawing
    int			        anim_total;				// total tenths in sequence ( 0 = no)
    int			        anim_min, anim_max;		// time for this frame min <=time< max
    struct texture_s    *anim_next;		        // in the animation sequence
    struct texture_s    *alternate_anims;	    // bmodels in frmae 1 use these
    unsigned	        offsets[MIPLEVELS];		// four mip maps stored
} texture_t;

#define	SURF_PLANEBACK		0x2
#define	SURF_DRAWSKY		0x4
#define SURF_DRAWSPRITE		0x8
#define SURF_DRAWTURB		0x10
#define SURF_DRAWTILED		0x20
#define SURF_DRAWBACKGROUND	0x40
#define SURF_UNDERWATER		0x80
//PENTA: Mirror surface
#define SURF_MIRROR			0x100
#define SURF_GLASS			0x200
#define SURF_CAULK			0x400
// extra water surface types
#define SURF_LAVA		    0x800
#define SURF_SLIME		    0x1000
#define SURF_TELE		    0x2000
#define SURF_WATER		    0x4000

// !!! if this is changed, it must be changed in asm_draw.h too !!!
typedef struct
{
    unsigned short	v[2];
    unsigned int	cachededgeoffset;
} medge_t;

typedef struct
{
    float		vecs[2][4];
    float		mipadjust;
    texture_t	*texture;
    int			flags;
} mtexinfo_t;

#define	VERTEXSIZE	7

//Penta
//I changed this the poly only stores the first index for the vertex in the global vertex list...
typedef struct glpoly_s
{
    struct	glpoly_s	*next;
    struct	glpoly_s	*chain;
    int		            numverts;
    int		            flags;			// for SURF_UNDERWATER
    int			        lightTimestamp;	//PENTA: timestamp of last light that this polygon was visible to
    struct	glpoly_s	**neighbours;
    int		            firstvertex;
} glpoly_t;

typedef struct msurface_s
{
    int			        visframe;				// should be drawn when node is crossed

    mplane_t	        *plane;
    int			        flags;

    int			        firstedge;				// look up in model->surfedges[], negative numbers
    int			        numedges;				// are backwards edges

    short		        texturemins[2];
    short		        extents[2];

    int			        light_s, light_t;		// gl lightmap coordinates

// Quake's normal doesn't take backfacing into account, so here's one that does
	vec3_t	            truenormal;

    glpoly_t	        *polys;					// multiple if warped
    struct	msurface_s	*texturechain;
    struct	msurface_s	*shadowchain;
    mtexinfo_t	        *texinfo;

// lighting info
    int			        lightmaptexturenum;
    byte		        styles[MAXLIGHTMAPS];
    byte		        *samples;				// [numstyles*surfsize]
} msurface_t;

typedef struct mnode_s
{
// common with leaf
    int			contents;		// 0, to differentiate from leafs
    int			visframe;		// node needs to be traversed if current

    float		minmaxs[6];		// for bounding box culling

    struct mnode_s	*parent;

// node specific
    mplane_t	*plane;
    struct mnode_s	*children[2];

    unsigned short		firstsurface;
    unsigned short		numsurfaces;
} mnode_t;



typedef struct mleaf_s
{
// common with node
    int			contents;		// wil be a negative contents number
    int			visframe;		// node needs to be traversed if current

    float		minmaxs[6];		// for bounding box culling

    struct mnode_s	*parent;

// leaf specific
    byte		*compressed_vis;
    efrag_t		*efrags;

    msurface_t	**firstmarksurface;
    int			nummarksurfaces;
    int			key;			// BSP sequence number for leaf's contents
    int			index;
    byte		ambient_sound_level[NUM_AMBIENTS];
} mleaf_t;

// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
    dclipnode_t	*clipnodes;
    mplane_t	*planes;
    int			firstclipnode;
    int			lastclipnode;
    vec3_t		clip_mins;
    vec3_t		clip_maxs;
} hull_t;

/*
==============================================================================

SPRITE MODELS

==============================================================================
*/


// FIXME: shorten these?
typedef struct mspriteframe_s
{
    int		width;
    int		height;
    float	up, down, left, right;
    int		gl_texturenum;
} mspriteframe_t;

typedef struct
{
    int				numframes;
    float			*intervals;
    mspriteframe_t	*frames[1];
} mspritegroup_t;

typedef struct
{
    spriteframetype_t	type;
    mspriteframe_t		*frameptr;
} mspriteframedesc_t;

typedef struct
{
    int					type;
    int					maxwidth;
    int					maxheight;
    int					numframes;
    float				beamlength;		// remove?
    void				*cachespot;		// remove?
    mspriteframedesc_t	frames[1];
} msprite_t;


/*
==============================================================================

ALIAS MODELS

Alias models are position independent, so the cache manager can move them.
==============================================================================
*/

typedef struct
{
    int					firstpose;
    int					numposes;
    float				interval;
    trivertx_t			bboxmin;
    trivertx_t			bboxmax;
    int					frame;
    char				name[16];
} maliasframedesc_t;

typedef struct
{
    trivertx_t			bboxmin;
    trivertx_t			bboxmax;
    int					frame;
} maliasgroupframedesc_t;

typedef struct
{
    int						numframes;
    int						intervals;
    maliasgroupframedesc_t	frames[1];
} maliasgroup_t;

// !!! if this is changed, it must be changed in asm_draw.h too !!!
//PENTA: no it's not we only modify opengl

typedef struct mtriangle_s
{
    int					facesfront;
    int					vertindex[3];
    int					neighbours[3];
} mtriangle_t;


#define	MAX_SKINS	32
typedef struct
{
    int			        ident;
    int			        version;
    vec3_t		        scale;
    vec3_t		        scale_origin;
    float		        boundingradius;
    vec3_t		        eyeposition;
    int			        numskins;
    int			        skinwidth;
    int			        skinheight;
    int			        numverts;
    int			        numtris;
    int			        numframes;
    synctype_t	        synctype;
    int			        flags;
    float		        size;

    vec3_t				mins, maxs;	// bounding box
    int					numposes;
    int					poseverts;
    int					posedata;	// numposes*poseverts trivert_t
    int					commands;	// gl command list with embedded s/t
    int					triangles;	//PENTA: We need tris for shadow volumes
    int					planes;		//PENTA: Plane eq's for every triangle for every frame
    int					tangents;	//PENTA: Tangent for every vertex for every frame
    int					binormals;	//PENTA: Tangent for every vertex for every frame
    int					texcoords;	//PENTA: For every triangle the 3 texture coords
    int					indecies; //PENTA: indecies for gl vertex arrays
    int					gl_texturenum[MAX_SKINS][4];
    int                 gl_lumatexturenum[MAX_SKINS][4]; // duh
    int					texels[MAX_SKINS];	// only for player skins
    maliasframedesc_t	frames[1];	// variable sized
} aliashdr_t;

#define	MAXALIASVERTS	2048
#define	MAXALIASFRAMES	256
#define	MAXALIASTRIS	2048
extern	aliashdr_t	*pheader;
extern	stvert_t	stverts[MAXALIASVERTS];
extern	mtriangle_t	triangles[MAXALIASTRIS];
extern	trivertx_t	*poseverts[MAXALIASFRAMES];

//===================================================================

//
// Whole model
//

typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;

#define	EF_ROCKET	1			// leave a trail
#define	EF_GRENADE	2			// leave a trail
#define	EF_GIB		4			// leave a trail
#define	EF_ROTATE	8			// rotate (bonus items)
#define	EF_TRACER	16			// green split trail
#define	EF_ZOMGIB	32			// small blood trail
#define	EF_TRACER2	64			// orange split trail + rotate
#define	EF_TRACER3	128			// purple trail
#define	EF_FASTVOLUME 256		// PENTA: fast shadow volume generation
#define	EF_FULLBRIGHT 512		// PENTA: draw model fullbright (lavaballs, torches, ...)
#define	EF_NOSHADOW 1024		//PENTA: don't draw any shadow

typedef struct model_s
{
    char		name[MAX_QPATH];
    qboolean	needload;		// bmodels and sprites don't cache normally

    modtype_t	type;
    int			numframes;
    synctype_t	synctype;

    int			flags;

//
// volume occupied by the model graphics
//
    vec3_t		mins, maxs;
    float		radius;

//
// solid volume for clipping
//
    qboolean	clipbox;
    vec3_t		clipmins, clipmaxs;

//
// brush model
//
    int			firstmodelsurface, nummodelsurfaces;

    int			numsubmodels;
    dmodel_t	*submodels;

    int			numplanes;
    mplane_t	*planes;

    int			numleafs;		// number of visible leafs, not counting 0
    mleaf_t		*leafs;

    int			numvertexes;
    mvertex_t	*vertexes;

    int			numedges;
    medge_t		*edges;

    int			numnodes;
    mnode_t		*nodes;

    int			numtexinfo;
    mtexinfo_t	*texinfo;

    int			numsurfaces;
    msurface_t	*surfaces;

    int			numsurfedges;
    int			*surfedges;

    int			numclipnodes;
    dclipnode_t	*clipnodes;

    int			nummarksurfaces;
    msurface_t	**marksurfaces;

    hull_t		hulls[MAX_MAP_HULLS];

    int			numtextures;
    texture_t	**textures;

    byte		*visdata;
    byte		*lightdata;
    char		*entities;

//
// additional model data
//
    cache_user_t	cache;		// only access through Mod_Extradata

} model_t;

//============================================================================

void	Mod_Init (void);
void	Mod_ClearAll (void);
model_t *Mod_ForName (char *name, qboolean crash);
void	*Mod_Extradata (model_t *mod);	// handles caching
void	Mod_TouchModel (char *name);
mleaf_t *Mod_PointInLeaf (float *p, model_t *model);
byte	*Mod_LeafPVS (mleaf_t *leaf, model_t *model);
float	Mod_RadiusFromBounds (vec3_t mins, vec3_t maxs);

#endif	// __MODEL__
